package com.senyint.hip.fhir.web;

import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.impl.GenericClient;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.senyint.hip.fhir.interceptor.CaptureInterceptor;

import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.exceptions.FHIRException;
import org.springframework.web.bind.annotation.*;

import java.util.Date;


/**
 * *******description*******
 * 院外检验报告
 * *************************
 *
 * @author ChenPan
 * @date 2018/10/31 10:14
 */
@RestController
@RequestMapping("/bundle")
public class BundleController extends FhirBaseController {

    @PostMapping()
    public String createReport(@RequestBody String reportStr) throws FHIRException {
        Bundle bundle = convertBundle(reportStr);

        CaptureInterceptor interceptor = new CaptureInterceptor();
        GenericClient client = newClient(tempData.getBaseServer(), interceptor);

        MethodOutcome out = client.create().resource(bundle).execute();

        return new Gson().toJson(out);

    }

    @PutMapping("/{id}")
    public String updateReport(@PathVariable("id") String id, @RequestBody String reportStr) throws FHIRException {
        Bundle bundle = convertBundle(reportStr);

        CaptureInterceptor interceptor = new CaptureInterceptor();
        GenericClient client = newClient(tempData.getBaseServer(), interceptor);

        MethodOutcome out = client.update(id, bundle);

        return new Gson().toJson(out);

    }

    protected Bundle convertBundle(String reportStr) throws FHIRException {
        JSONObject jsonObject = JSON.parseObject(reportStr);

        Encounter encounter = new Encounter();

        encounter.addIdentifier()
                .setValue("S100");
        encounter.setStatus(Encounter.EncounterStatus.FINISHED);
        //就诊类型
        encounter.setClass_(new Coding()
                .setSystem("http://hl7.org/fhir/v3/ActCode")
                .setCode(jsonObject.getString("visitTypeCode"))
                .setDisplay(jsonObject.getString("visitTypeName")));

        encounter.setSubject(new Reference("Patient/d1"));
        encounter.addType(new CodeableConcept().setText(jsonObject.getString("deptName")));
        //就诊时间
        encounter.setPeriod(new Period().setStart(jsonObject.getDate("visitTime")).setEnd(jsonObject.getDate("dischargeTime")));

        Composition composition = new Composition();
        composition.setId(IdDt.newRandomUuid());
        composition.setStatus(Composition.CompositionStatus.FINAL);
        composition.getType()
                .setText(jsonObject.getString("docTypeName"))
                .addCoding()
                .setSystem("http://loinc.org")
                .setCode(jsonObject.getString("docTypeCode"));
        composition.getSubject().setDisplay(jsonObject.getString("patientName"))
                .setReference("http://www.hl7.org.cn/open/Patient/d1");
        composition.setEncounter(new Reference(encounter.getId()));
         
    
        if(StringUtils.isNotBlank(jsonObject.getString("reportDate"))) {
        	composition.setDate(jsonObject.getDate("reportDate"));
        	
        }else {
        	
        	 composition.setDate(new Date());
        }
         
        
       
        composition.addAuthor().setDisplay(jsonObject.getString("author"))
                .setReference("Practitioner/example");
        composition.setTitle(jsonObject.getString("docTitle"));
        composition.setConfidentiality(Composition.DocumentConfidentiality.N);

        // Create a patient object
        Patient patient = new Patient();
        patient.setId("d1");
        patient.setActive(true);
        patient.addName()
                .setText(jsonObject.getString("patientName"));

        patient.getTelecom().add(new ContactPoint()
                .setSystem(ContactPoint.ContactPointSystem.PHONE)
                .setValue(jsonObject.getString("telephone"))
                .setUse(ContactPoint.ContactPointUse.WORK));
        patient.setGender(Enumerations.AdministrativeGender.fromCode(jsonObject.getString("sex")));
        patient.setBirthDate(jsonObject.getDate("birthDate"));
        patient.getAddress().add(new Address().setUse(Address.AddressUse.HOME).addLine(jsonObject.getString("homeAddr")));


        // Create a bundle that will be used as a transaction
        Bundle bundle = new Bundle();

        bundle.setIdentifier(new Identifier().setSystem("urn:ietf:rfc:3986").setValue(jsonObject.getString("identifier")));
        bundle.setType(Bundle.BundleType.DOCUMENT);

        bundle.addEntry()
                .setResource(composition)
                .getRequest()
                .setUrl("Composition")
                .setMethod(Bundle.HTTPVerb.POST);


        bundle.addEntry()
                .setResource(patient)
                .getRequest()
                .setUrl("Patient")
//				.setIfNoneExist("identifier=http://acme.org/mrns|12345")
                .setMethod(Bundle.HTTPVerb.POST);

        bundle.addEntry()
                .setResource(encounter)
                .getRequest()
                .setUrl("Encounter")
                .setMethod(Bundle.HTTPVerb.POST);
        
       if("检验报告".equals(jsonObject.getString("docTypeName"))) {
        Observation report = new Observation();
        report.setCode(
                new CodeableConcept().addCoding(new Coding()
                        .setCode(jsonObject.getString("code"))
                        .setDisplay(jsonObject.getString("display"))
                ).setText(jsonObject.getString("text")));
        report.setSpecimen(new Reference().setDisplay(jsonObject.getString("sample")));
        bundle.addEntry()
                .setResource(report)
                .getRequest()
                .setUrl("Observation")
                .setMethod(Bundle.HTTPVerb.POST);


        JSONArray subItem = jsonObject.getJSONArray("subItem");
        for (int i = 0; i < subItem.size(); i++) {
            JSONObject sub = subItem.getJSONObject(i);

            Observation ob = new Observation();

            ob.setId(sub.getString("no"));
            ob.setStatus(Observation.ObservationStatus.FINAL);
            ob.getCode()
                    .setText(sub.getString("display"))
                    .addCoding().setSystem("http://loinc.org")
                    .setCode(sub.getString("code"))
                    .setDisplay(sub.getString("display"));

            ob.setSubject(new Reference().setDisplay(jsonObject.getString("patientName")));
            ob.addPerformer(new Reference().setDisplay(jsonObject.getString("tester")));
            ob.setValue(new Quantity()
                    .setValue(sub.getDouble("value"))
                    .setUnit(sub.getString("unit")));
            SimpleQuantity low = new SimpleQuantity();
            if (sub.get("low") != null && !"".equals(sub.getString("low"))) {

                low.setValue(sub.getDouble("low"));
            }
            low.setUnit(sub.getString("unit"));

            SimpleQuantity high = new SimpleQuantity();
            if (sub.get("high") != null && !"".equals(sub.getString("high"))) {

                high.setValue(sub.getDouble("high"));
            }
            high.setUnit(sub.getString("unit"));

            ob.addReferenceRange(new Observation.ObservationReferenceRangeComponent().setLow(low).setHigh(high));


            bundle.addEntry()
                    .setResource(ob)
                    .getRequest()
                    .setUrl("Observation")
                    .setMethod(Bundle.HTTPVerb.POST);

        }}else {
        	  Observation report = new Observation();
              report.setId(jsonObject.getString("no"));
              report.setStatus(Observation.ObservationStatus.FINAL);
              report.addCategory(new CodeableConcept().addCoding(new Coding().setSystem("http://hl7.org/fhir/observation-category").setCode(jsonObject.getString("categoryCode")).setDisplay(jsonObject.getString("categoryName"))));
              report.setCode(
                      new CodeableConcept().addCoding(new Coding().setSystem("http://loinc.org")
                              .setCode(jsonObject.getString("code"))
                              .setDisplay(jsonObject.getString("display"))
                      ).setText(jsonObject.getString("text")));
              
              
            
              report.setSubject(new Reference().setDisplay(jsonObject.getString("patientName")));

              report.setEffective(new DateTimeType(jsonObject.getDate("effectiveDateTime")));
              report.addPerformer(new Reference().setReference("Practitioner/f005").setDisplay(jsonObject.getString("tester")));
              report.setValue(new StringType(jsonObject.getString("result")));
              report.setBodySite(new CodeableConcept().setText(jsonObject.getString("bodySiteName")).addCoding(new Coding().setSystem("http://snomed.info/sct").setCode(jsonObject.getString("bodySiteCode"))));
              report.setMethod(new CodeableConcept().setText(jsonObject.getString("methodName")).addCoding(new Coding().setSystem("http://snomed.info/sct").setCode(jsonObject.getString("methodCode"))));
              report.setDevice(new Reference().setDisplay(jsonObject.getString("device")));
              bundle.addEntry()
                      .setResource(report)
                      .getRequest()
                      .setUrl("Observation")
                      .setMethod(Bundle.HTTPVerb.POST);
        
        }

        return bundle;
    }
    

}
